package cn.com.chengmandian.core.web.filters;

import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.common.constants.ResponseCode;
import cn.com.chengmandian.core.common.enums.ClientsEnum;
import cn.com.chengmandian.core.common.utils.UrlUtil;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.pojo.LoginUser;
import cn.com.chengmandian.core.web.properties.AuthProperties;
import cn.com.chengmandian.core.web.utils.AuthUtil;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Slf4j
@Component
public class RequestAuthFilter extends OncePerRequestFilter {
    @Autowired
    private AuthProperties authProperties;

    // 403 权限不足
    private void responseError(HttpServletResponse response, Integer code, String message) {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(JSONUtil.toJsonStr(AjaxResult.error(code, message)));
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    // 默认白名单
    private static final List<String> defaultWhiteList = ListUtil.toList(
            "/*/swagger-resources",
            "/*/swagger-resources/**",
            "/*/swagger-ui/**",
            "/*/v3/api-docs",
            "/*/inner/**",// 内部接口
            "/*/outer/**");// 外部接口

    private void printRequest(HttpServletRequest request) {
        if (!SpringContextUtil.isDev()) return;
        log.info("=============================================================");
        log.info("RequestURI:{}", request.getRequestURI());
        if (request.getParameterMap() != null && request.getParameterMap().size() > 0) {
            log.info("ParameterMap:{}", JSONUtil.toJsonStr(request.getParameterMap()));
        }
        log.info("=============================================================");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        printRequest(request);
        if (!authProperties.getEnable()) {
            filterChain.doFilter(request, response);
            return;
        }
        String requestURI = request.getRequestURI();
        if (CollectionUtil.isNotEmpty(authProperties.getWhiteList())) {
            for (String path : authProperties.getWhiteList()) {
                if (UrlUtil.filterUrls(path, requestURI)) {
                    filterChain.doFilter(request, response);
                    return;
                }
            }
        }
        for (String path : defaultWhiteList) {
            if (UrlUtil.filterUrls(path, requestURI)) {
                filterChain.doFilter(request, response);
                return;
            }
        }
        String clientId = request.getHeader(CommonConstant.HEADER_CLIENT_ID);
        if (StrUtil.isBlank(clientId)) {
            responseError(response, ResponseCode.ACCESS_DENIED, "缺少客户端标识");
            return;
        }
        ClientsEnum client = ClientsEnum.codeOf(clientId);
        if (client == null) {
            responseError(response, ResponseCode.ACCESS_DENIED, "客户端错误");
            return;
        }

        // 如果应用配置了用户类型
        if (StrUtil.isNotEmpty(authProperties.getUserType())) {
            // 如果配置的用户类型和提交的客户端用户类型不匹配
            if (!ArrayUtil.contains(authProperties.getUserType().split(","), client.getUserType())) {
                responseError(response, ResponseCode.ACCESS_DENIED, "非法用户类型");
                return;
            }
        }

        // 获取，并校验
        LoginUser loginUser = AuthUtil.getLoginUser(request, client);
        if (loginUser == null) {
            responseError(response, ResponseCode.TOKEN_INVALID, "登录信息失效：" + request.getRequestURI());
            return;
        }
        filterChain.doFilter(request, response);
    }

}
